package com.dd.cloud.user.service.plat.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.constants.PlatConstants;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.utils.JsonUtils;
import com.dd.cloud.common.utils.ObjectUtils;
import com.dd.cloud.common.utils.Sha1Util;
import com.dd.cloud.common.utils.StringOperUtil;
import com.dd.cloud.user.config.TencentImProperties;
import com.dd.cloud.user.config.WechatConfig;
import com.dd.cloud.user.config.WechatPayConfig;
import com.dd.cloud.user.entity.plat.PlatformWechatInfo;
import com.dd.cloud.user.enums.ExceptionEnum;
import com.dd.cloud.user.mapper.plat.PlatformWechatInfoMapper;
import com.dd.cloud.user.req.plat.ShareWechatSignReq;
import com.dd.cloud.user.req.template.TemplateMessageGzhReq;
import com.dd.cloud.user.req.template.TemplateMessageGzhRes;
import com.dd.cloud.user.req.template.TemplateMessageReq;
import com.dd.cloud.user.req.template.TemplateMessageRes;
import com.dd.cloud.user.res.plat.ShareWechatInfo;
import com.dd.cloud.user.res.plat.TencentImUserSig;
import com.dd.cloud.user.service.log.ILogErrorService;
import com.dd.cloud.user.service.plat.IPlatformLoginService;
import com.dd.cloud.user.service.plat.IPlatformWechatInfoService;
import com.dd.cloud.user.util.TLSSigAPIv2;
import com.dd.cloud.user.util.WxUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 第三方登录信息表 服务实现类
 * </p>
 *
 * @author czg
 * @since 2022-05-06
 */
@Service
@Slf4j
public class PlatformWechatInfoServiceImpl extends ServiceImpl<PlatformWechatInfoMapper, PlatformWechatInfo> implements IPlatformWechatInfoService {
    @Autowired
    private WechatConfig wechatConfig;
    @Autowired
    private WechatPayConfig wechatPayConfig;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private TencentImProperties tencentImProperties;
    @Autowired
    private IPlatformLoginService platformLoginService;
    @Autowired
    private ILogErrorService logErrorService;
    @Autowired
    private WxUtil wxUtil;


    /**
     * 微信分享返回的数据
     *
     * @param shareUrl
     * @return
     */
    @Override
    public ShareWechatInfo shareWechatInfo(String shareUrl) {
        String ticket = redisTemplate.opsForValue().get(PlatConstants.TICKETWECHAT);
        if (StringUtils.isBlank(ticket)) {
            String accessToken = platformLoginService.getAccessToken();
            String ticketUrl = String.format(wechatConfig.getShareWechatTicket(), accessToken);
            String ticketRes = restTemplate.getForObject(ticketUrl, String.class);
            Map<String, String> ticketMap = JsonUtils.parseMap(ticketRes, String.class, String.class);
            if (!ticketMap.get("errcode").equals("0")) {
                throw new ZekeException(ExceptionEnum.SHART_WX_ERROR, ticketMap.get("errmsg"));
            }
            ticket = ticketMap.get("ticket");
            int timeSecond = Integer.valueOf(ticketMap.get("expires_in"));
            redisTemplate.boundValueOps(PlatConstants.TICKETWECHAT).set(ticket, timeSecond, TimeUnit.SECONDS);
        }
        ShareWechatSignReq signObj = new ShareWechatSignReq();
        signObj.setTimestamp(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
        signObj.setNonceStr(StringOperUtil.getRandomString(16));
        signObj.setUrl(shareUrl);
        String signStr = ticket + "&" + ObjectUtils.pinyinSort(signObj);
        String sign = Sha1Util.getSha1(signStr);
        ShareWechatInfo info = new ShareWechatInfo();
        info.setAppId(wechatPayConfig.getAppId());
        info.setNonceStr(signObj.getNonceStr());
        info.setTimestamp(signObj.getTimestamp());
        info.setSignature(sign);
        return info;
    }

    /**
     * 返回腾讯云即时通信的参数
     */
    @Override
    public TencentImProperties tencentImSecret() {
        return tencentImProperties;
    }

    /**
     * @param id:   用户id
     * @param type: 用户类型 同登录类型
     * @return TencentImUserSig 用户签名信息
     * @description 获取腾讯云im即时通信的用户签名 医生->医生id_医生类型  患者->患者id_患者类型_就诊id
     * @author czg
     * @date 2023/7/5 16:47
     */
    @Override
    public TencentImUserSig tencentImUserSig(Integer id, Integer type, String medId) {
        TLSSigAPIv2 tlsSigAPIv2 = new TLSSigAPIv2(tencentImProperties.getSdkappid(), tencentImProperties.getKey());
        String user = id + "_" + type;
        if (!StringUtils.isBlank(medId)) {
            user = user + "_" + medId;
        }
        String userSig = tlsSigAPIv2.genUserSig(user, tencentImProperties.getExpire());
        TencentImUserSig tencentImUserSig = new TencentImUserSig();
        tencentImUserSig.setUserSig(userSig);
        tencentImUserSig.setExpire(tencentImUserSig.getExpire());
        return tencentImUserSig;
    }


    @Override
    public void sendTemplateMessage(TemplateMessageReq req, String accessToken) {
        String url = String.format(wechatConfig.getSubscribeMessage(), accessToken);
        HttpEntity<TemplateMessageReq> entity = new HttpEntity<>(req);
        ResponseEntity<TemplateMessageRes> exchange = restTemplate.exchange(url, HttpMethod.POST, entity, TemplateMessageRes.class);
        log.info("发送订阅消息响应信息：{}", JSON.toJSONString(exchange));
        if (exchange.getStatusCode().value() != HttpStatus.OK.value() || Objects.requireNonNull(exchange.getBody()).getErrcode() != 0) {
            log.error("发送订阅消息发送异常，请求地址：{},请求参数：{},响应结果:{}", url, JSON.toJSONString(req), JSON.toJSONString(exchange));
            logErrorService.presBackLog("订阅消息发送失败", "", "");
        }
    }

    /**
     * 发送模板
     *
     * @param req
     * @param accessToken
     */
    @Override
    public Boolean sendTemplateMessageGzh(TemplateMessageGzhReq req, String accessToken) {
        String url = String.format(wechatConfig.getSubscribeMessageGzh(), accessToken);
        HttpEntity<TemplateMessageGzhReq> entity = new HttpEntity<>(req);
        ResponseEntity<TemplateMessageGzhRes> exchange = restTemplate.exchange(url, HttpMethod.POST, entity, TemplateMessageGzhRes.class);
        log.info("发送订阅消息响应信息：{}", JSON.toJSONString(exchange));
        if (exchange.getStatusCode().value() != HttpStatus.OK.value() || Objects.requireNonNull(exchange.getBody()).getErrcode() != 0) {
            log.error("发送订阅消息发送异常，请求地址：{},请求参数：{},响应结果:{}", url, JSON.toJSONString(req), JSON.toJSONString(exchange));
            logErrorService.presBackLog("订阅消息发送失败", "", "");
            return false;
        }
        return true;
    }

    /**
     * @param request:
     * @return String
     * @description 微信事件回调
     * @author czg
     * @date 2023/10/11 13:54
     */
    @Override
    public String handlePublicMsg(HttpServletRequest request) {
        log.error("进入推送消息方法");
        // 获得微信端返回的xml数据
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        try {
            is = request.getInputStream();
            isr = new InputStreamReader(is, StandardCharsets.UTF_8);
            br = new BufferedReader(isr);
            String str;
            StringBuffer returnXml = new StringBuffer();
            while ((str = br.readLine()) != null) {
                //返回的是xml数据
                returnXml.append(str);
            }
            Map<String, String> encryptMap = StringOperUtil.xmlToMap(returnXml.toString());
            log.error(encryptMap.toString());
            // 得到公众号传来的加密信息并解密,得到的是明文xml数据
            //String decryptXml = WXPublicUtils.decrypt(encryptMap.get("Encrypt"));
            // 将xml数据转换为map
            /*logger.error(decryptXml.toString());
            Map<String, String> decryptMap = VatifyToken.xmlToMap(decryptXml.toString());*/
            Map<String, String> decryptMap = encryptMap;
            // 区分消息类型
            String msgType = decryptMap.get("MsgType");
            //场景信息
            String eventKey = decryptMap.get("EventKey");
            // 普通消息
            if ("text".equals(msgType)) { // 文本消息
                // todo 处理文本消息
            } else if ("image".equals(msgType)) { // 图片消息
                // todo 处理图片消息
            } else if ("voice".equals(msgType)) { //语音消息
                // todo 处理语音消息
            } else if ("video".equals(msgType)) { // 视频消息
                // todo 处理视频消息
            } else if ("shortvideo".equals(msgType)) { // 小视频消息
                // todo 处理小视频消息
            } else if ("location".equals(msgType)) { // 地理位置消息
                // todo 处理地理位置消息
            } else if ("link".equals(msgType)) { // 链接消息
                // todo 处理链接消息
            }
            // 事件推送
            else if ("event".equals(msgType)) { // 事件消息
                // 区分事件推送
                String event = decryptMap.get("Event");
                log.error("区分事件推送:" + event);
                if ("subscribe".equals(event)) { // 订阅事件 或 未关注扫描二维码事件
                    String mapToXml = wxUtil.getReturnMessage1(decryptMap, eventKey);
                    log.error("发送数据:" + mapToXml);
                    return mapToXml;
                } else if ("unsubscribe".equals(event)) { // 取消订阅事件
                    // todo 处理取消订阅事件
                } else if ("SCAN".equals(event)) { // 已关注扫描二维码事件
                    String mapToXml = wxUtil.getReturnMessage1(decryptMap, eventKey);
                    log.error("发送数据:" + mapToXml);
                    return mapToXml;
                } else if ("LOCATION".equals(event)) { // 上报地理位置事件
                    // todo 处理上报地理位置事件
                } else if ("CLICK".equals(event)) { // 点击菜单拉取消息时的事件推送事件
                    // todo 处理点击菜单拉取消息时的事件推送事件
                } else if ("VIEW".equals(event)) { // 点击菜单跳转链接时的事件推送
                    // todo 处理点击菜单跳转链接时的事件推送
                }
            }
        } catch (Exception e) {
            log.error("处理微信公众号请求信息，失败", e);
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (null != isr) {
                try {
                    isr.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return null;
    }

    /**
     * @param request:
     * @param menuJson:
     * @return String
     * @description 自定义发布公众号菜单
     * @author czg
     * @date 2023/10/12 9:16
     */
    @Override
    public String wxPublicMenu(HttpServletRequest request, String menuJson) {
        String accessToken = platformLoginService.getAccessToken();
        String url = String.format(wechatConfig.getPublicAccountMenu(), accessToken);
        String res = restTemplate.postForObject(url, menuJson, String.class);
        log.info("微信公众号菜单发布返回:{}", res);
        return null;
    }
}
